查漏补缺第一期(Redis相关) 您所在的位置:网站首页 redis cluster重启 查漏补缺第一期(Redis相关)

查漏补缺第一期(Redis相关)

2023-05-22 09:09| 来源: 网络整理| 查看: 265

前言

目前正在出一个查漏补缺专题系列教程, 篇幅会较多, 喜欢的话,给个关注❤️ ~

本专题主要以Java语言为主, 好了, 废话不多说直接开整吧~

Q1 & 请介绍一下redis的架构

Redis是一种开源的高性能键值存储系统,通常被用作内存数据库、缓存和消息中间件。它具有简单、灵活、高效的特点,以及丰富的数据结构和功能,使其成为许多应用程序的首选。

Redis的架构主要由以下几个关键组件组成:

客户端:应用程序通过Redis客户端与Redis服务器进行通信。客户端可以使用多种编程语言和协议与Redis进行交互,如Redis的官方客户端库、REST API或其他第三方客户端。

服务器:Redis服务器是Redis的核心组件,负责处理客户端请求、执行命令和存储数据。服务器使用单线程事件循环模型,通过监听网络连接和处理事件来实现高并发和低延迟的性能。

数据存储:Redis支持多种数据结构,包括字符串、哈希表、列表、集合和有序集合等。这些数据结构都可以通过唯一的键来进行访问和操作。Redis的数据存储是基于内存的,但也可以通过持久化机制将数据写入磁盘,以便在服务器重启时进行恢复。

内存管理:Redis通过使用自定义的内存分配器来管理内存,以提高性能并减少内存碎片。它使用了多种技术,如对象共享、对象池和内存压缩,来有效地管理内存使用。

高可用性:为了实现高可用性和数据冗余,Redis提供了主从复制和哨兵机制。主从复制通过将数据从主服务器复制到多个从服务器,实现数据的冗余备份和读写分离。哨兵机制用于监控和管理Redis服务器集群,当主服务器发生故障时,自动选举新的主服务器。

集群模式:Redis还提供了集群模式,可以将数据分片存储在多个节点上,实现水平扩展和负载均衡。集群模式使用哈希槽来划分数据,每个节点负责管理一部分哈希槽的数据。

总体而言,Redis的架构设计简单而灵活,适用于各种场景。它的高性能、丰富的数据结构和功能,使其成为处理大规模数据、高并发访问和实时应用的理想选择。

Q2 & 请详细讲一下redis的线程模型

Redis的线程模型采用的是单线程的事件循环模型,也称为I/O多路复用模型。

单线程模型: Redis使用单线程来处理所有的客户端请求和数据库操作。这意味着Redis在任何给定的时间只能处理一个请求,但通过事件循环机制,它能够高效地处理大量并发请求。

事件循环: Redis使用事件循环来实现高并发和低延迟的性能。事件循环是通过I/O多路复用技术实现的,通常使用select、poll或epoll等系统调用。Redis通过监听套接字上的事件,如可读、可写或异常事件,来感知和处理客户端请求。

非阻塞I/O: Redis使用非阻塞I/O来实现事件循环。在接收到客户端请求时,Redis不会阻塞等待请求完成,而是立即返回到事件循环并继续处理其他请求。当请求的I/O操作完成时,Redis会通过回调函数来处理响应数据。

文件事件: Redis使用文件事件来表示与客户端或其他网络连接相关的事件。每当有新的客户端连接或数据到达时,Redis会生成相应的文件事件并将其加入到事件队列中。事件循环会从队列中获取文件事件并处理它们。

时间事件: Redis还支持时间事件,用于执行定时任务。时间事件可以是一次性的,也可以是周期性的。通过时间事件,Redis可以执行诸如过期键的清理、统计信息的更新等后台任务。

非阻塞操作: Redis的数据存储是基于内存的,因此读写操作通常是非阻塞的。这使得Redis能够在快速的内存访问下提供高性能的读写操作。

多个数据库: Redis支持多个数据库,每个数据库都有自己的键值空间。在单线程模型下,Redis使用字典来存储数据库,通过索引来快速访问不同的数据库。

通过以上的线程模型,Redis能够高效地处理大量的并发请求,而无需为每个请求创建线程或进程。单线程模型可以避免线程切换和同步开销,提供较低的延迟和较高的吞吐量。同时,Redis通过使用非阻塞I/O和事件驱动的方式,实现了高效的事件处理和资源利用。

下面我们使用Java来简单的仿写一下单线程模型

public class Q2 { public static void main(String[] args) throws InterruptedException { RedisTaskQueue taskQueue = new RedisTaskQueue(); RedisEventLoop eventLoop = new RedisEventLoop(taskQueue); RedisClient client = new RedisClient(taskQueue); // 启动事件处理器线程 Thread eventLoopThread = new Thread(eventLoop); eventLoopThread.start(); // 模拟客户端发送命令 client.sendCommand("SET key1 value1"); client.sendCommand("GET key1"); client.sendCommand("DEL key1"); // 等待所有命令执行完成 eventLoopThread.join(); // Executing Redis command: SET key1 value1 // Executing Redis command: GET key1 // Executing Redis command: DEL key1 } } // 模拟Redis命令的执行任务 class RedisCommandTask { private String command; public RedisCommandTask(String command) { this.command = command; } public void execute() { // 模拟命令的执行 System.out.println("Executing Redis command: " + command); } } // 模拟Redis的任务队列 class RedisTaskQueue { private Queue queue = new LinkedList(); public synchronized void enqueue(RedisCommandTask task) { queue.add(task); notify(); // 通知等待中的线程有新任务 } public synchronized RedisCommandTask dequeue() throws InterruptedException { while (queue.isEmpty()) { wait(); // 如果队列为空,则等待新任务的到来 } return queue.poll(); } } // 模拟Redis的事件处理器 class RedisEventLoop implements Runnable { private RedisTaskQueue taskQueue; public RedisEventLoop(RedisTaskQueue taskQueue) { this.taskQueue = taskQueue; } @Override public void run() { while (true) { try { RedisCommandTask task = taskQueue.dequeue(); task.execute(); } catch (InterruptedException e) { Thread.currentThread().interrupt(); break; } } } } // 模拟Redis的客户端 class RedisClient { private RedisTaskQueue taskQueue; public RedisClient(RedisTaskQueue taskQueue) { this.taskQueue = taskQueue; } public void sendCommand(String command) { RedisCommandTask task = new RedisCommandTask(command); taskQueue.enqueue(task); } }

使用synchronized关键字实现了任务队列的线程安全性。enqueue()方法用于将任务添加到队列中,并使用notify()通知等待中的线程有新任务可执行。dequeue()方法则在队列为空时调用wait()进入等待状态,直到有新任务到来时被唤醒。

事件处理器线程在start()方法中通过循环不断从任务队列中取出任务并执行。如果队列为空,线程会调用wait()方法进入等待状态,直到有新任务到来。这样保证了事件处理器在没有任务时不会空转消耗CPU资源。

主程序中创建了一个RedisClient实例,并通过sendCommand()方法模拟了客户端发送命令的过程。每个命令都被封装成RedisCommandTask对象,并通过任务队列传递给事件处理器线程执行。这种方式模拟了Redis的非阻塞命令执行,即命令被添加到任务队列后,客户端可以继续发送其他命令而无需等待命令执行完成。

Q3 & 请详细讲一下redis的非阻塞式IO和多路复用

Redis使用非阻塞式I/O和多路复用技术来实现高性能的事件驱动模型。

非阻塞式I/O: 非阻塞式I/O是一种I/O操作的模式,在进行读取或写入操作时,不会阻塞线程等待操作完成。Redis使用非阻塞I/O来实现事件驱动模型,它的实现原理如下:

设置套接字为非阻塞模式:Redis在接受客户端连接或创建套接字时,将套接字设置为非阻塞模式。这样,在进行读取或写入操作时,不会阻塞线程,而是立即返回。

非阻塞的读取操作:当Redis执行读取操作时,它会检查套接字上是否有数据可读。如果没有数据可读,读取操作会立即返回,避免线程阻塞。Redis可以使用非阻塞的方式读取数据,以便处理其他事件。

非阻塞的写入操作:当Redis执行写入操作时,它会检查套接字是否可写。如果套接字不可写,写入操作会立即返回,避免线程阻塞。Redis可以使用非阻塞的方式写入数据,以便处理其他事件。

多路复用: 多路复用是一种I/O多路复用技术,用于同时监视多个套接字上的事件。Redis使用多路复用技术来管理多个套接字上的事件,以实现高效的事件驱动模型。下面是多路复用的实现原理:

注册事件和套接字:Redis将需要监听的套接字注册到多路复用器中,并指定事件类型,如可读、可写或异常。

多路复用器监听事件:多路复用器负责监听所有已注册套接字上的事件。它使用系统调用(如select、poll或epoll)来监视套接字上的事件状态。

事件就绪通知:当套接字上的事件状态发生变化时,多路复用器会通知Redis。这样,Redis可以及时处理事件。

事件处理:一旦事件就绪,Redis会调用相应的事件处理函数来处理事件。例如,如果有可读事件就绪,Redis会调用读取数据的函数来处理请求。

通过非阻塞式I/O和多路复用的组合,Redis实现了高效的事件驱动模型。非阻塞式I/O使得Redis能够在进行读取或写入操作时不会阻塞线程,提高了并发处理能力。

多路复用技术允许Redis同时监听多个套接字上的事件,提供高效的事件管理和触发能力。这种组合使得Redis能够处理大量并发请求,提供高性能和低延迟的服务。

下面通过Java简单的演示一下非阻塞式I/O和多路复用

import java.io.IOException; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.channels.*; import java.util.Iterator; public class NonBlockingServer { public static void main(String[] args) throws IOException { ServerSocketChannel serverChannel = ServerSocketChannel.open(); serverChannel.configureBlocking(false); serverChannel.bind(new InetSocketAddress(8888)); Selector selector = Selector.open(); serverChannel.register(selector, SelectionKey.OP_ACCEPT); while (true) { selector.select(); Iterator iterator = selector.selectedKeys().iterator(); while (iterator.hasNext()) { SelectionKey key = iterator.next(); iterator.remove(); if (key.isAcceptable()) { ServerSocketChannel serverSocketChannel = (ServerSocketChannel) key.channel(); SocketChannel clientChannel = serverSocketChannel.accept(); clientChannel.configureBlocking(false); clientChannel.register(selector, SelectionKey.OP_READ); } else if (key.isReadable()) { SocketChannel clientChannel = (SocketChannel) key.channel(); ByteBuffer buffer = ByteBuffer.allocate(1024); int bytesRead = clientChannel.read(buffer); if (bytesRead > 0) { buffer.flip(); byte[] data = new byte[buffer.remaining()]; buffer.get(data); String message = new String(data); System.out.println("Received message: " + message); } clientChannel.close(); } } } } }

这个示例中,我们创建了一个非阻塞的服务器,使用ServerSocketChannel进行监听,并将其注册到Selector上。然后,在循环中,调用selector.select()等待事件发生。当有事件发生时,通过遍历selectedKeys来处理事件。如果事件是OP_ACCEPT,表示有新的客户端连接,我们接受连接并将客户端的SocketChannel注册到Selector上,监听可读事件OP_READ。如果事件是OP_READ,表示有数据可读,我们读取数据并处理。

结束语

大家可以针对自己薄弱的地方进行复习, 然后多总结,形成自己的理解,不要去背~

本着把自己知道的都告诉大家,如果本文对您有所帮助,点赞+关注鼓励一下呗~

项目源码(源码已更新 欢迎star⭐️) java-interview-all: https://github.com/qiuChengleiy/java-interview-all 往期设计模式相关文章 一起来学设计模式之认识设计模式 一起来学设计模式之单例模式 一起来学设计模式之工厂模式 一起来学设计模式之建造者模式 一起来学设计模式之原型模式 一起来学设计模式之适配器模式 一起来学设计模式之桥接模式 一起来学设计模式之组合模式 一起来学设计模式之装饰器模式 一起来学设计模式之外观模式 一起来学设计模式之享元模式 一起来学设计模式之代理模式 一起来学设计模式之责任链模式 一起来学设计模式之命令模式 一起来学设计模式之解释器模式 一起来学设计模式之迭代器模式 一起来学设计模式之中介者模式 一起来学设计模式之备忘录模式 一起来学设计模式之观察者模式 一起来学设计模式之状态模式 一起来学设计模式之策略模式 一起来学设计模式之模板方法模式 一起来学设计模式之访问者模式 一起来学设计模式之依赖注入模式 设计模式项目源码(源码已更新 欢迎star⭐️) java-design-mode-all: https://github.com/qiuChengleiy/java-design-mode-all Kafka 专题学习 一起来学kafka之Kafka集群搭建 一起来学kafka之整合SpringBoot基本使用 一起来学kafka之整合SpringBoot深入使用(一) 一起来学kafka之整合SpringBoot深入使用(二) 一起来学kafka之整合SpringBoot深入使用(三) 项目源码(源码已更新 欢迎star⭐️) springboot-kafka-all: https://github.com/qiuChengleiy/springboot-kafka-all ElasticSearch 专题学习

利用docker搭建es集群

一起来学ElasticSearch(一)

一起来学ElasticSearch(二)

一起来学ElasticSearch(三)

一起来学ElasticSearch(四)

一起来学ElasticSearch(五)

一起来学ElasticSearch(六)

一起来学ElasticSearch(七)

一起来学ElasticSearch(八)

一起来学ElasticSearch(九)

一起来学ElasticSearch(十)

一起来学ElasticSearch之整合SpringBoot(一)

一起来学ElasticSearch之整合SpringBoot(二)

一起来学ElasticSearch之整合SpringBoot(三)

项目源码(源码已更新 欢迎star⭐️) springboot-es-all: https://github.com/qiuChengleiy/springboot-es-all 往期并发编程内容推荐 Java多线程专题之线程与进程概述 Java多线程专题之线程类和接口入门 Java多线程专题之进阶学习Thread(含源码分析) Java多线程专题之Callable、Future与FutureTask(含源码分析) 面试官: 有了解过线程组和线程优先级吗 面试官: 说一下线程的生命周期过程 面试官: 说一下线程间的通信 面试官: 说一下Java的共享内存模型 面试官: 有了解过指令重排吗,什么是happens-before 面试官: 有了解过volatile关键字吗 说说看 面试官: 有了解过Synchronized吗 说说看 Java多线程专题之Lock锁的使用 面试官: 有了解过ReentrantLock的底层实现吗?说说看 面试官: 有了解过CAS和原子操作吗?说说看 Java多线程专题之线程池的基本使用 面试官: 有了解过线程池的工作原理吗?说说看 面试官: 线程池是如何做到线程复用的?有了解过吗,说说看 面试官: 阻塞队列有了解过吗?说说看 面试官: 阻塞队列的底层实现有了解过吗? 说说看 面试官: 同步容器和并发容器有用过吗? 说说看 面试官: CopyOnWrite容器有了解过吗? 说说看 面试官: Semaphore在项目中有使用过吗?说说看(源码剖析) 面试官: Exchanger在项目中有使用过吗?说说看(源码剖析) 面试官: CountDownLatch有了解过吗?说说看(源码剖析) 面试官: CyclicBarrier有了解过吗?说说看(源码剖析) 面试官: Phaser有了解过吗?说说看 面试官: Fork/Join 有了解过吗?说说看(含源码分析) 面试官: Stream并行流有了解过吗?说说看 推荐 SpringBoot & SpringCloud (源码已更新 欢迎star⭐️)

springboot-all

地址: github.com/qiuChenglei…

SpringBoot系列教程合集

一起来学SpringCloud合集

SpringCloud整合 Oauth2+Gateway+Jwt+Nacos 实现授权码模式的服务认证(一)

SpringCloud整合 Oauth2+Gateway+Jwt+Nacos 实现授权码模式的服务认证(二)

博客(阅读体验较佳) 我的博客(阅读体验较佳)


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有